﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MegavaniaX.World;
using MegavaniaX.Messaging.Events;
using MegavaniaX.Actors.Weapons;
using MegavaniaX.Actors.States;


namespace MegavaniaX
{
    /// <summary>
    /// Class for the main player character.  (Megaman!)
    /// </summary>
    public class Player : Actor
    {
        // Animations
        public Animation animationIdle;
        public Animation animationMove;
        public Animation animationJump;
        public Animation animationSlide;
        public Animation animationShootIdle;
        public Animation animationShootMoving;
        public Animation animationShootJumping;
        public Animation animationClimb;

        // weapons
        private IList<WeaponBase> _weapons;
        private WeaponBase _currentWeapon;

        /// <summary>
        /// The default speed of this actor, in the X direction.
        /// </summary>
        public float defaultSpeedX = 0.12f;

        public const float InitialXVelo = 0.12f;
        public const float InitialYVelo = -0.30f;
        public const float InitialSlideVelo = 0.12f;
        public const float ClimbSpeed = -0.10f;

        /// <summary>
        /// The default speed of this actor, in the Y direction.
        /// </summary>
        public float defaultSpeedY = 0.0010f;
        // public float defaultSpeedY = 0.00005f; // floaty jump!

        private float slideSpeedX = 0.15f;

        public bool IsSliding = false;

        public bool IsMoving = false;

        public bool IsShooting = false;

        public bool IsClimbing = false;

        public static TimeSpan SlideDuration = new TimeSpan(0, 0, 0, 0, 600);

        private DateTime currentSlideStarted = DateTime.Now;        

        public const int NormalHeight = 24;
        public const int SlideHeight = 15;

        /** ENERGY / HEALTH **/
        public int MaxEnergy
        {
            get;
            protected set;
        }
        public int Energy
        {
            get;
            protected set;
        }


        public Player(String id) : base(id)
        {
            // properties
            IsAffectedByGravity = true;
            IsAffectedByWalls = true;
            IsPlayer = true;


            animationIdle = AnimationManager.MakeAnimation("player_idle");
            animationMove = AnimationManager.MakeAnimation("player_moveright");
            animationJump = AnimationManager.MakeAnimation("player_jumpright");
            animationSlide = AnimationManager.MakeAnimation("player_slideright");
            animationClimb = AnimationManager.MakeAnimation("player_climb");

            animationShootIdle = AnimationManager.MakeAnimation("player_shootidle");
            animationShootIdle.Subscribe(OnShootAnimationFinished, MegavaniaEventType.AnimationComplete, "player");
            animationShootMoving = AnimationManager.MakeAnimation("player_shootmove");
            animationShootMoving.Subscribe(OnShootAnimationFinished, MegavaniaEventType.AnimationComplete, "player");
            animationShootJumping = AnimationManager.MakeAnimation("player_shootjump");
            animationShootJumping.Subscribe(OnShootAnimationFinished, MegavaniaEventType.AnimationComplete, "player");

            CurrentAnimation = animationIdle;

            // event subscriptions (sounds)
            Subscribe(Sound.SoundManager.PlaySoundEvent, MegavaniaEventType.PlaySound, "soundman");

            // event subscriptions (world manager)
            Subscribe(MapManager.OnSpawnActor, MegavaniaEventType.SpawnActor, "world");
            Subscribe(MapManager.OnScreenTransistionStart, MegavaniaEventType.ScreenTransistionStart, "world");
            MessagingSystem.SubscribeToEvent(MapManager.OnScreenTransistionEnd, MegavaniaEventType.ScreenTransistionEnd, null);

            // initialize weapons
            _weapons = new List<WeaponBase>();
            _weapons.Add(new Buster(this));
            _weapons.Add(new Magnet(this));
            _currentWeapon = _weapons.Single(x => x.GetType() == typeof(Buster));

            MaxEnergy = 10;
            Energy = MaxEnergy;

            // initialize state machine
            var idleState = new PlayerStateIdle(this);
            StateMachine = new StateMachine(idleState);


            Height = NormalHeight;
            Width = 21;

        }
        
        public void HandleEvent(IMegavaniaEvent evt)
        {
            StateMachine.HandleEvent(evt);
        }


        /// <summary>
        /// Event handler for the player moving right.
        /// </summary>
        /// <param name="evt"></param>
        public void MoveRightPressed(IMegavaniaEvent evt)
        {
            IsFacingLeft = false;
            if (!IsAirborne)
                CurrentAnimation = animationMove;
            else
                CurrentAnimation = animationJump;
            velocity.X = defaultSpeedX;
            IsMoving = true;
        }

        /// <summary>
        /// Event handler for the player releasing the right key.
        /// </summary>
        /// <param name="evt"></param>
        public void MoveRightReleased(IMegavaniaEvent evt)
        {
            if (velocity.X > 0.0f)
            {
                if (!IsAirborne)
                    CurrentAnimation = animationIdle;
                velocity.X = 0.0f;
                IsMoving = false;
            }
        }

        /// <summary>
        /// Event handler for the player pressing the move left button.
        /// </summary>
        /// <param name="evt"></param>
        public void MoveLeftPressed(IMegavaniaEvent evt)
        {
            IsFacingLeft = true;
            if (!IsAirborne)
            {
                CurrentAnimation = animationMove;
            }
            else
            {
                CurrentAnimation = animationJump;                
            }
            if (velocity.X <= 0.0f)
            {
                velocity.X = -(defaultSpeedX);
            }
            else
            {
                velocity.X = -velocity.X;
            }
            IsMoving = true;
        }

        /// <summary>
        /// Event handler for the player pressing the move right button.
        /// </summary>
        /// <param name="evt"></param>
        public void MoveLeftReleased(IMegavaniaEvent evt)
        {
            if (velocity.X < 0.0f)
            {
                if (!IsAirborne)
                    CurrentAnimation = animationIdle;
                velocity.X = 0.0f;
                IsMoving = false;
            }
        }

        public void OnJumpPressed(IMegavaniaEvent evt)
        {
            // MegavaniaX.logger.Debug(string.Format("Actor {0}: jump pressed", ActorID));
            if (!IsAirborne)
            {
                // velocity.Y = -0.25f;
                velocity.Y = -0.30f;
                acceleration.Y = defaultSpeedY;
                CurrentAnimation = animationJump;
                IsAirborne = true;
                // stop sliding
                if (IsSliding)
                {
                    Height = NormalHeight;
                    this.position.Y = this.position.Y - (NormalHeight - SlideHeight);
                    IsSliding = false;
                }
            }            
        }

        public void OnJumpReleased(IMegavaniaEvent evt)
        {
            if (IsAirborne)
            {
                if (velocity.Y < 0.0f)
                {
                    velocity.Y = 0.0f;
                }                
            }
        }

        public void OnSlidePressed(IMegavaniaEvent evt)
        {
            if (!IsAirborne) // sliding only works on ground, obviously
            {
                if (velocity.X < 0.0f || IsFacingLeft)
                {
                    velocity.X = -slideSpeedX;
                }
                else
                {
                    velocity.X = slideSpeedX;
                    
                }
                CurrentAnimation = animationSlide;
                IsSliding = true;
                this.Height = SlideHeight;
                this.position.Y = this.position.Y + (NormalHeight - SlideHeight);
                currentSlideStarted = DateTime.Now;
            }
        }

        public void OnShootPressed(IMegavaniaEvent evt)
        {            
            //if (!IsShooting) // if already shooting, don't do anything
            //{
                WeaponEvent weaponEvent = (WeaponEvent)evt;             

                if (StateMachine.CurrentState.CanHandleEvent(evt.EventType))
                {
                    StateMachine.CurrentState.HandleEvent(evt);
                    _currentWeapon.FirePrimary(weaponEvent.Modifiers);
                }

            //}
        }

        public void OnShootAnimationFinished(IMegavaniaEvent evt)
        {
            IsShooting = false;
            
            if (IsAirborne)
            {
                CurrentAnimation = animationJump;
            }
            else if (velocity.X != 0.0f)
            {
                CurrentAnimation = animationMove;
            }
            else
            {
                CurrentAnimation = animationIdle;
            }
        }        

        /// <summary>
        /// Gets the current sprite of this object.
        /// </summary>
        /// <returns></returns>
        public override MegavaniaSprite CurrentSprite()
        {
            return CurrentAnimation.CurrentSprite();
        }

        #region Weapon Change Event Handlers

        public void ChangeWeapon(IMegavaniaEvent evt)
        {
            WeaponChangeEvent e = (WeaponChangeEvent)evt;
            // for now we'll ignore the parameter and just switch between buster and magnet
            if (_currentWeapon.WeaponName == "buster")
                _currentWeapon = _weapons.Single(x => x.WeaponName == "magnet");
            else
                _currentWeapon = _weapons.Single(x => x.WeaponName == "buster");
        }


        #endregion


    }
}
